#ifndef WXSITEMEDITORCONTENT_H
#define WXSITEMEDITORCONTENT_H

#include "wxsdrawingwindow.h"

class wxsItemEditorDragAssist;
class wxsItemResData;
class wxsItemEditor;
class wxsItemInfo;
class wxsParent;
class wxsItem;

class wxsItemEditorContent: public wxsDrawingWindow {
  public:
    wxsItemEditorContent( wxWindow* Parent, wxsItemResData* Data, wxsItemEditor* Editor );
    virtual ~wxsItemEditorContent();
    void BeforePreviewChanged();
    void AfterPreviewChanged();
    void RefreshSelection();
    void InsertByPointing( const wxsItemInfo* Info );

  protected:

    virtual void PaintExtra( wxDC* DC );
    virtual void ScreenShootTaken();

  private:

    enum DragBoxType {
      LeftTop = 0,
      Top,
      RightTop,
      Left,
      Right,
      LeftBtm,
      Btm,
      RightBtm,
      DragBoxTypeCnt
    };

    enum MouseStatesT {
      msIdle,
      msDraggingPointInit,
      msDraggingPoint,
      msDraggingItemInit,
      msDraggingItem,
      msTargetSearch,
      msWaitForIdle,
    };

    struct DragPointData {
      wxsItem* Item;                                  ///< \brief Associated item
      DragBoxType Type;                               ///< \brief Type of this drag box
      bool Grey;                                      ///< \brief If true, this drag point will be drawn grey
      int PosX;                                       ///< \brief X position of this drag point
      int PosY;                                       ///< \brief Y position of this drag point
      int DragInitPosX;                               ///< \brief X position before dragging
      int DragInitPosY;                               ///< \brief Y position before dragging
      DragPointData* ItemPoints[DragBoxTypeCnt];      ///< \brief Pointers to all drag points for this item
    };

    WX_DEFINE_ARRAY( DragPointData*, DragPointsT );
    WX_DECLARE_VOIDPTR_HASH_MAP( wxRect, ItemToRectT );
    WX_DECLARE_VOIDPTR_HASH_MAP( wxWindow*, ItemToWindowT );

    wxsItemResData* m_Data;                             ///< \brief Data of handled resource
    wxsItemEditor* M_Code_Editor;                            ///< \brief Main editor class
    DragPointsT m_DragPoints;                           ///< \brief Array of visible drag points
    ItemToRectT m_ItemToRect;                           ///< \brief Coordinates of each item stored here
    ItemToWindowT m_ItemToWindow;                       ///< \brief Window in editor area for each item is stored here
    bool m_RebuildMaps;                                 ///< \brief Set to true when internal maps need to be recalculated
    MouseStatesT m_MouseState;                          ///< \brief Current mouse state
    static const int m_DragBoxSize = 6;                 ///< \brief Size of boxes used to drag borders of widgets
    static const int m_MinDragDistance = 8;
    DragPointData* m_CurDragPoint;                      ///< \brief Dragged drag point
    wxsItem*       m_CurDragItem;                       ///< \brief Dragged item
    int            m_DragInitPosX;                      ///< \brief Initial mouse x position when dragging
    int            m_DragInitPosY;
    wxsItemEditorDragAssist* m_Assist;                  ///< \brief Assisting class
    wxsItem*   m_AssistTarget;
    wxsParent* m_AssistParent;
    bool       m_AssistAddAfter;

    const wxsItemInfo* m_TargetInfo;                    ///< \brief Info of item added by pointing with mouse
    int m_TargetX;
    int m_TargetY;
    void OnMouse( wxMouseEvent& event );
    void OnMouseIdle( wxMouseEvent& event );
    void OnMouseDraggingPoint( wxMouseEvent& event );
    void OnMouseDraggingPointInit( wxMouseEvent& event );
    void OnMouseDraggingItem( wxMouseEvent& event );
    void OnMouseDraggingItemInit( wxMouseEvent& event );
    void OnMouseTargetSearch( wxMouseEvent& event );
    void OnKeyDown( wxKeyEvent& event );
    inline void SetCur( int Cur ) { SetCursor( wxCursor( Cur ) ); }
    void RebuildDragPoints();
    void ClearDragPoints();
    void GreyDragPoints();
    void AddDragPoints( wxsItem* Item, wxsItem* RootSelection );
    void UpdateDragPoints( DragPointData* anyPoint );

    wxsItem* FindItemAtPos( int PosX, int PosY, wxsItem* SearchIn );
    DragPointData* FindDragPointAtPos( int PosX, int PosY );
    DragPointData* FindDragPointFromItem( wxsItem* Item );
    bool FindDraggingItemTarget( int PosX, int PosY, wxsItem* Dragging, wxsParent*& NewParent, wxsItem*& AtCursor, bool& AddAfter );
    bool FindAbsoluteRect( wxsItem* Item, int& PosX, int& PosY, int& SizeX, int& SizeY );
    wxWindow* GetPreviewWindow( wxsItem* Item );
    void ClearMaps();
    void RecalculateMaps();
    void RecalculateMapsReq( wxsItem* Item );
    void AddItemAtTarget( wxsParent* AssistParent, int Position, const wxsItemInfo* Info, int PosX, int PosY );
    void GridFixup( wxWindow* PreviewWindow, int& PosX, int& PosY );
    void GridFixupForGlobalCoordinates( int& PosX, int& PosY, wxsItem* Owner );
    static bool IsContinousInsert();
    friend class wxsItemEditorDragAssist;
    DECLARE_EVENT_TABLE()
};

#endif
